# -*- coding: utf-8 -*-
import math
import sys

from PyQt5.QtCore import Qt, QRectF
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *


class WidgetDashboard(QWidget):
    def __init__(self, *args, **kwargs):
        text = kwargs.pop("text", "")
        super(WidgetDashboard, self).__init__(*args, **kwargs)
        self.InitUI()

    def InitUI(self):
        self.maxValue = 100  # 最大值
        self.minValue = 0  # 最小值
        self.startAngle = 45  # 起始位置（deg,从正下方顺时针开始）
        self.endAngle = 45  # 终止位置（deg,从正下方逆时针开始）
        self.scaleMajor = 10  # 刻度数量
        self.currentValue = 0  # 当前标识值
        self.startPieRatio = 0.1  # 区块1占据比例
        self.midPieRatio = 0.8  # 区块2占据比例
        self.endPieRatio = 0.1  # 区块3占据比例

        # meter以200，200的矩形为原始绘制区域，所以半径最大设置为100
        self.ringOuterRadius = 100  # 圆环外圈半径
        self.ringInnerRadius = 90  # 圆环内卷半径

        self.pointerLength = 60  # 指针长度
        self.scaleLineRadius = 90  # 刻度值外环半径
        self.scaleLineLength = 5  # 刻度标记线长度
        self.scaleScaleLineWidth = 4  # 刻度标记线粗
        self.unitStr = "°"  # 刻度单位文字
        self.textRingRadious = 70  # 刻度标记文字环半径

        self.lcd_refpos_x = 0.4  # LCD显示位置 X轴坐标 0~1，代表从左到右，0.5在正中间
        self.lcd_refpos_y = 0.8  # LCD显示位置 Y轴坐标，0~1，代表从上到下
        self.lcd_refsize_height = 0.2  # LCD相对控件的高度，0.1代表LCD大小为控件的10%
        self.lcd_refsize_width = 0.2  # LCD相对控件的宽度
        self.digitCount = 2  # LCD最多显示两位数字

        # 窗口初始化
        # self.setWindowTitle("QPainter测试")
        self.setMinimumSize(200, 200)
        # self._title = '__title__'

        # 颜色设置
        self.pieColorStart = QColor(63, 191, 127, 255)  # 绿色
        self.pieColorMid = QColor(255, 255, 255)  # 蓝色
        self.pieColorEnd = QColor(255, 0, 0)  # 红色
        self.pointerColor = QColor(72, 203, 203)  # 青色
        self.scaleColorStart = self.pieColorStart
        self.scaleColorMid = self.pieColorMid
        self.scaleColorEnd = self.pieColorEnd

        self.scaleFontColor = QColor(26, 95, 95)

        # 设置字符
        self.font = QFont("Noto Sans S Chinese Bold", 12)
        # self.font.setBold(True)

        # LCD初始化
        self.lcd_init()

    # 设置标题接口
    def setTitle(self, title):
        self._title = title

    # 设置取值接口
    def setValue(self, value):
        self.currentValue = value
        self.update()

    def lcd_init(self):
        # print("display")
        self.lcd = QLCDNumber(self)
        self.lcd.setSmallDecimalPoint(False)  # False：小数点单独占一位；True：小数点不占位
        self.lcd.setDigitCount(self.digitCount)  # 最多显示2位数字
        self.lcd.setFrameStyle(QFrame.NoFrame)  # 无边框
        self.lcd.setMode(QLCDNumber.Dec)  # 十进制显示
        self.lcd.setStyleSheet("color: rgb(26, 95, 95)")  # 显示数字的颜色
        self.lcd.setSegmentStyle(QLCDNumber.Flat)  # 数字显示样式为flat，不向外凸

    def paintEvent(self, event):
        # 坐标轴变换 默认640*480
        width = self.width()
        height = self.height()

        painter = QPainter(self)  # 初始化painter
        painter.translate(width / 2, height / 2)  # 坐标轴变换，调用translate()将坐标原点平移至窗口中心

        # 坐标刻度自适应
        side = min(width, height)
        painter.scale(side / 200.0, side / 200.0)
        # 本项目中将坐标缩小为side/200倍，即画出length=10的直线，其实际长度应为10*(side/200)。

        # 启用反锯齿，使画出的曲线更平滑
        painter.setRenderHints(QPainter.Antialiasing | QPainter.TextAntialiasing)
        painter.begin(self)

        # 开始画图
        self.drawLine(painter)
        self.drawColorPie(painter)
        self.drawPointerIndicator(painter)
        # print("drawPointerIndicator called")

        self.drawText(painter)
        # self.drawTitle(painter)
        painter.end()

        # 放置lcd并显示数值
        # 根据自己控件的大小调整lcd的位置
        self.lcd.setGeometry(self.width() * self.lcd_refpos_x, self.height() * self.lcd_refpos_y,
                             self.width() * self.lcd_refsize_width,
                             self.height() * self.lcd_refsize_height)  # 用setGeometry布局 2.25 , 9*7, 10,10
        formValue = "%d" % self.currentValue  # 数值的格式化显示
        self.lcd.display(formValue)  # 将指针所指的值显示在LCD屏幕上

    def drawColorPie(self, painter):  # 绘制三色环
        painter.save()  # save()保存当前坐标系
        # print("drawColorPie")
        # 设置扇形部分区域
        radius = self.ringOuterRadius  # 圆环外圈半径
        painter.setPen(Qt.NoPen)
        rect = QRectF(-radius, -radius, radius * 2, radius * 2)  # 扇形所在圆区域

        # 计算三色圆环范围角度。green：blue：red = 1：2：1

        angleAll = 360.0 - self.startAngle - self.endAngle  # self.startAngle = 45, self.endAngle = 45
        angleStart = angleAll * self.startPieRatio
        angleMid = angleAll * self.midPieRatio
        angleEnd = angleAll * self.endPieRatio

        # 圆的中心部分填充为透明色，形成环的样式
        rg = QRadialGradient(0, 0, radius, 0, 0)  # 起始圆心坐标，半径，焦点坐标
        ratio = self.ringInnerRadius / self.ringOuterRadius  # 计算圆环内外环半径比

        # 绘制绿色环
        rg.setColorAt(0, Qt.transparent)  # 透明色
        rg.setColorAt(ratio, Qt.transparent)
        rg.setColorAt(ratio + 0.01, self.pieColorStart)
        rg.setColorAt(1, self.pieColorStart)

        painter.setBrush(rg)
        painter.drawPie(rect, (270 - self.startAngle - angleStart) * 16, angleStart * 16)

        # 绘制蓝色环
        rg.setColorAt(0, Qt.transparent)
        rg.setColorAt(ratio, Qt.transparent)
        rg.setColorAt(ratio + 0.01, self.pieColorMid)
        rg.setColorAt(1, self.pieColorMid)

        painter.setBrush(rg)
        painter.drawPie(rect, (270 - self.startAngle - angleStart - angleMid) * 16, angleMid * 16)

        # 绘制红色环
        rg.setColorAt(0, Qt.transparent)
        rg.setColorAt(ratio, Qt.transparent)
        rg.setColorAt(ratio + 0.01, self.pieColorEnd)
        rg.setColorAt(1, self.pieColorEnd)

        painter.setBrush(rg)
        painter.drawPie(rect, (270 - self.startAngle - angleStart - angleMid - angleEnd) * 16, angleEnd * 16)

        painter.restore()  # restore()恢复坐标系

    def drawPointerIndicator(self, painter):
        painter.save()
        # 绘制指针
        # print("drawPointerIndicator")
        radius = self.pointerLength  # 指针长度
        painter.setPen(Qt.NoPen)
        painter.setBrush(self.pointerColor)

        # (-5, 0), (0, -8), (5, 0)和（0, radius) 四个点绘出指针形状
        # 绘制多边形做指针
        pts = QPolygon()
        pts.setPoints(-5, 0, 0, -8, 5, 0, 0, radius)
        # print("radius:" + str(radius))

        # 旋转指针，使得指针起始指向为0刻度处
        painter.rotate(self.startAngle)
        degRotate = (360.0 - self.startAngle - self.endAngle) / (self.maxValue - self.minValue) \
                    * (self.currentValue - self.minValue)
        painter.rotate(degRotate)
        painter.drawConvexPolygon(pts)
        painter.restore()

    def drawText(self, painter):
        painter.save()
        # 绘制刻度值
        # print("drawText")
        # 位置调整
        startRad = (270 - self.startAngle) / 180 * 3.1415926
        deltaRad = (360 - self.endAngle - self.startAngle) / self.scaleMajor * 3.1415926 / 180
        radius = self.textRingRadious
        offset = 5.5
        for i in range(self.scaleMajor + 1):  # self.scaleMajor = 8, 8个主刻度
            # 正余弦计算
            sina = math.sin(startRad - i * deltaRad)
            cosa = math.cos(startRad - i * deltaRad)

            # 刻度值计算
            value = math.ceil((1.0 * i * (
                    (self.maxValue - self.minValue) / self.scaleMajor) + self.minValue))
            # math.ceil(x)：返回不小于x的最小整数
            strValue = str(int(value))

            # 字符的宽度和高度
            textWidth = self.fontMetrics().width(strValue)
            textHeight = self.fontMetrics().height()

            # 字符串的起始位置。注意考虑到字符宽度和高度进行微调
            x = radius * cosa - textWidth / 2
            y = -radius * sina + textHeight / 4

            painter.setFont(self.font)
            painter.setPen(self.scaleFontColor)
            painter.drawText(x - offset, y, strValue + self.unitStr)
            # Y为自己加的单位，可以不加，直接在 Title 中进行总体设置也行
        painter.restore()

    def drawLine(self, painter):
        painter.save()
        # 绘制刻度线
        # print("drawLine")
        radius = self.scaleLineRadius
        painter.rotate(self.startAngle)  # self.startAngle = 45,旋转45度
        steps = self.scaleMajor  # 8个刻度
        angleStep = (360.0 - self.startAngle - self.endAngle) / steps  # 刻度角
        for i in range(steps + 1):
            color = QColor(255, 255, 255)
            # if i*1.0 / steps < self.startPieRatio:
            #     color = self.scaleColorStart
            # elif i*1.0 / steps < (self.startPieRatio + self.midPieRatio):
            #     color = self.scaleColorMid
            # else:
            #     color = self.scaleColorEnd
            painter.setPen(QPen(color, self.scaleScaleLineWidth, Qt.SolidLine))
            painter.drawLine(0, radius - self.scaleLineLength, 0, radius + 3)
            painter.rotate(angleStep)
        painter.restore()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    demo = WidgetDashboard()
    demo.show()
    demo.setValue(6)  # 设置指针指向
    # demo.setTitle("Title_____")  # 设置图标题
    sys.exit(app.exec_())
